package com.xquant.pricing.calc.service.impl.otcOption.split;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.xquant.common.core.constant.DictConstant;
import com.xquant.pricing.calc.entity.CalcEngineParam4Simple;
import com.xquant.pricing.calc.entity.simple.*;
import com.xquant.pricing.calc.service.StockService;
import com.xquant.common.engine.xPP.request.CalcEngineParam;
import com.xquant.common.engine.xPP.request.CalcPricingParam;
import com.xquant.common.engine.xPP.request.Instrument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 功能说明：保本价差期权拆分
 * 编写作者：botao.yu
 * 开发日期：2021/11/5 18:47
 * 修改记录：修改日期   修改人    修改内容
 */
@Component
public class CalcCommonService4OtcOptionSplit4SpreadSnow implements CalcCommonService4OtcOptionSplit {
    @Autowired
    private StockService stockService;

    @Override
    public CalcEngineParam split(CalcEngineParam4Simple sourceCalcEngineParam) {
        CalcEngineParam engineParam = new CalcEngineParam();
        engineParam.setPriority("h");
        engineParam.setLocalLog("1");
        Instrument instrument = new Instrument();
        instrument.setProductType(DictConstant.OPTION_TYPE.ELN_ACB_VANILLASPREAD.getCode());
        Record record = sourceCalcEngineParam.getRecord();
        BaseInfo baseInfo = record.getBaseInfo();
        OptionTrade OptionTrade = record.getOptionTrade();
        String productType = null;
        List<PremiumItem> premiumList = null;
        if (OptionTrade != null) {
            premiumList = OptionTrade.getPremium();
        }
        List<OptionLeg> legDataList = OptionTrade.getOptionLegs();
        LegData legData = null;
        if (legDataList.size() > 0) {
            productType = legDataList.get(0).getProductType();
            legData = legDataList.get(0).getLegData();
        }
        if (legData != null) {
            JSONObject termData = new JSONObject();
            //雪球结构拼装
            termData.put("productType", DictConstant.OPTION_TYPE.ELN_ACB_VANILLASPREAD.getCode());
            termData.put("notional", legData.getNotional());
            termData.put("term", legData.getTerm());
            termData.put("notionalCurrency", "CNY");
            termData.put("payDirection", DictConstant.IR_DIRECT.SELL.equals(legData.getTrdType()) ? DictConstant.DIRECT.SELL : DictConstant.DIRECT.BUY);
            termData.put("effectiveDate", legData.getEffectiveDate());
            termData.put("effectiveDateConv", "Unadjusted");
            termData.put("terminationDate", legData.getTerminationDate());
            termData.put("terminationDateConv", "Unadjusted");
            termData.put("terminationDateCalendar", "CHINA_EX");
            termData.put("interestBearingMargin", "");
            JSONObject marginObj = new JSONObject();
            marginObj.put("marginAmount", "0");
            marginObj.put("overLoss", "0");
            termData.put("margin", marginObj);
            legData.setUnderlyerId(getInstructionId((String) legData.getUnderlyerId()));
            Map qryMap = new HashMap();
            qryMap.put("stockCode", legData.getUnderlyerId());
            qryMap.put("calDate", DateUtil.today());
            //去当前标的的最近收盘价
            Map priceMap = stockService.queryLastDateStockPrice(qryMap);
            termData.put("issuePrice", legData.getSpotPrice());
            if (StrUtil.isNotBlank(MapUtil.getStr(priceMap, "DP_CLOSE"))) {
                termData.put("issuePrice", MapUtil.getStr(priceMap, "DP_CLOSE"));
            }
            String[] underLyerArray = {legData.getUnderlyerId()};
            termData.put("underlyerIds", underLyerArray);
            termData.put("calendars", new String[]{"CHINA_EX"});
            JSONObject underLyerJSON = new JSONObject();
            JSONArray underLyerJSONArray = new JSONArray();
            underLyerJSON.put("instrumentId", legData.getUnderlyerId());
            underLyerJSONArray.add(underLyerJSON);
            termData.put("underlyers", underLyerJSONArray);
            JSONObject knockOutObj = new JSONObject();
            knockOutObj.put("observeType", "NULL_TYPE");
            knockOutObj.put("observeRounding", "4");
            knockOutObj.put("payDirection", DictConstant.IR_DIRECT.SELL.equals(legData.getTrdType()) ? DictConstant.DIRECT.SELL : DictConstant.DIRECT.BUY);
            //保底收益率
            JSONObject basicYieldObj = new JSONObject();
            MinimumYield[] miniYield = legData.getMinimumYields();
            if (miniYield.length > 0) {
                basicYieldObj.put("daycounter", transferBasic(miniYield[0].getDayCounter(), miniYield[0].getIfAnnual()));
                basicYieldObj.put("paymentAmountPecentage", miniYield[0].getYieldRate());
                basicYieldObj.put("participationRate", "1");
            }
            JSONArray knoksArray = new JSONArray();
            JSONObject observeDate = new JSONObject();
            observeDate.put("endDate", legData.getEffectiveDate());
            observeDate.put("endDateConv", "Unadjusted");
            observeDate.put("calendar", "CHINA_IB");
            JSONObject calclationPeriod = new JSONObject();
            calclationPeriod.put("startDate", legData.getEffectiveDate());
            calclationPeriod.put("startDateConv", "Following");
            calclationPeriod.put("isIncludeStartDate", legData.getKnockOut().getCalclationPeriodInclude());
            calclationPeriod.put("endDate", legData.getEffectiveDate());
            calclationPeriod.put("endDateConv", "Following");
            calclationPeriod.put("isIncludeEndDate", legData.getKnockOut().getCalclationPeriodInclude());
            calclationPeriod.put("calendar", "CHINA_EX");
            calclationPeriod.put("frequency", "1D");
            //得到敲出结构中的观察日期价格比例和票据数组
            String[] obsDateArray = StrUtil.isNotBlank(legData.getKnockOut().getObserveDates()) ? legData.getKnockOut().getObserveDates().split(";") : null;
            //敲出价格比例
            String[] triggerLevelRatesArray = StrUtil.isNotBlank(legData.getKnockOut().getTriggerLevelRates()) ? legData.getKnockOut().getTriggerLevelRates().split(";") : null;
            //票息
            String[] rebateRatesArray = StrUtil.isNotBlank(legData.getKnockOut().getRebateRates()) ? legData.getKnockOut().getRebateRates().split(";") : null;
            if (obsDateArray != null) {
                for (int i = 0; i < obsDateArray.length; i++) {
                    JSONObject knocksObj = new JSONObject();
                    JSONObject triggerObj = new JSONObject();
                    triggerObj.put("type", "EqualOrGreater");
                    triggerObj.put("levelPercentage", "1");//敲出比例 默认100
                    knocksObj.put("trigger", triggerObj);
                    observeDate.put("endDate", obsDateArray[i]);
                    knocksObj.put("observeDate", JSON.parseObject(JSON.toJSONString(observeDate)));
                    if (i == 0) {
                        calclationPeriod.put("startDate", legData.getEffectiveDate());
                    } else {
                        calclationPeriod.put("startDate", obsDateArray[i - 1]);
                    }
                    calclationPeriod.put("endDate", obsDateArray[i]);
                    knocksObj.put("calclationPeriod", JSON.parseObject(JSON.toJSONString(calclationPeriod)));
                    knocksObj.put("paymentDate", obsDateArray[i]);
                    knocksObj.put("paymentDateOffset", legData.getKnockOut().getPaymentDateOffset());
                    knocksObj.put("paymentDateConv", "Unadjusted");
                    knocksObj.put("paymentDateCalendar", "CHINA_IB");
                    JSONObject yeildObj = new JSONObject();
                    yeildObj.put("daycounter", transferBasic(legData.getMinimumYields()[0].getDayCounter(), legData.getMinimumYields()[0].getIfAnnual()));
                    yeildObj.put("paymentAmountPecentage", rebateRatesArray[i]);
                    yeildObj.put("participationRate", triggerLevelRatesArray[i]);
                    knocksObj.put("basicYield", yeildObj);
                    knoksArray.add(knocksObj);
                }
            }
            knockOutObj.put("knocks", knoksArray);
            termData.put("knockOut", knockOutObj);
            JSONObject unTriggerObj = new JSONObject();
            unTriggerObj.put("payDirection", DictConstant.IR_DIRECT.SELL.equals(legData.getTrdType()) ? DictConstant.DIRECT.SELL : DictConstant.DIRECT.BUY);
            unTriggerObj.put("unTriggerType", "NoKnockInAndNoKnockOut");
            JSONObject calclationPeriodObj = new JSONObject();
            calclationPeriodObj.put("startDate", legData.getEffectiveDate());
            calclationPeriodObj.put("startDateConv", "Following");
            calclationPeriodObj.put("isIncludeStartDate", legData.getKnockOut().getCalclationPeriodInclude());
            calclationPeriodObj.put("isIncludeEndDate", legData.getKnockOut().getCalclationPeriodInclude());
            calclationPeriodObj.put("endDate", legData.getTerminationDate());
            calclationPeriodObj.put("endDateConv", "Following");
            calclationPeriodObj.put("calendar", "CHINA_EX");
            calclationPeriodObj.put("frequency", "1D");
            unTriggerObj.put("calclationPeriod", calclationPeriodObj);
            JSONObject embeddedStructureObj = new JSONObject();
            JSONObject vanillaSpreadObj = new JSONObject();
            vanillaSpreadObj.put("payDirection", DictConstant.IR_DIRECT.SELL.equals(legData.getTrdType()) ? DictConstant.DIRECT.SELL : DictConstant.DIRECT.BUY);
            vanillaSpreadObj.put("optionType", null);
            vanillaSpreadObj.put("fixingRounding", 4);
            vanillaSpreadObj.put("spreadType", legData.getUnTrigger().getEmbeddedStructure().getVanillaSpread().getSpreadType());
            vanillaSpreadObj.put("quoteType", "Close");
            vanillaSpreadObj.put("exerciseDate", legData.getTerminationDate());
            vanillaSpreadObj.put("daycounter", transferBasic(miniYield[0].getDayCounter(), miniYield[0].getIfAnnual()));
            vanillaSpreadObj.put("participationRate", "1");
            vanillaSpreadObj.put("downStrike", legData.getUnTrigger().getEmbeddedStructure().getVanillaSpread().getLowerStrikeRate());
            vanillaSpreadObj.put("upStrike", legData.getUnTrigger().getEmbeddedStructure().getVanillaSpread().getUpperStrikeRate());
            embeddedStructureObj.put("vanillaSpread", vanillaSpreadObj);
            unTriggerObj.put("embeddedStructure", embeddedStructureObj);
            unTriggerObj.put("basicYield", basicYieldObj);
            unTriggerObj.put("paymentDate", legData.getTerminationDate());
            unTriggerObj.put("paymentDateConv", "Following");
            unTriggerObj.put("paymentDateCalendar", "CHINA_EX");
            termData.put("unTrigger", unTriggerObj);
            instrument.setTermsheet(termData);
            instrument.setProductType(DictConstant.OPTION_TYPE.ELN_ACB_VANILLASPREAD.getCode());
            engineParam.setInstrument(instrument);
            CalcPricingParam calPriceParamObj = new CalcPricingParam();
            calPriceParamObj.setValueDate(getCalcDate(sourceCalcEngineParam));
//            calPriceParamObj.setCalcPPCode("PhoenixOrSnowball_MC");
            engineParam.setCalcPricingParam(calPriceParamObj);
            return engineParam;
        }
        return null;
    }

    @Override
    public CalcEngineParam split(CalcEngineParam sourceCalcEngineParam) {
        return null;
    }

    @Override
    public String getSplitCode() {
        return DictConstant.OPTION_TYPE.ELN_ACB_VANILLASPREAD.getCode();
    }


}
